[Xamarin.Mac] コレクションビューを使用してみました
1 はじめに
CX事業本部の平内(SIN)です。
Xamarin.Macを使用すると、C#でネイティブなMacのアプリが作成可能です。 ここでは、私自身がXamarin.Macに入門して学習した事項を覚書として書かせて頂いています。
今回は、コレクションビューを使用してみました。
コレクションビューは、テーブルビューやアウトラインビューと違って、個々のアイテムを表示するための組み込みビューがありません。 これを独自に用意する必要がある事から、やや、ハードルの高いものとなっているかも知れません。
2 CollectionViewの配置
Interface Builderで、メインとなるビューにCollection Viewを配置し、ウインドウいっぱいに表示されるように制約を追加します。
また、AssistantエディタでViewController.hを開いてOutletを接続します。 ( 接続するコントロールがNSCollectionViewになっていることに注意が必要です。)
3 ビューの作成
ファイル > 新しいファイル > Mac > View Controllerと辿り、新規にビューを作成します。(ここでは、名前をMyItemとしました)
この時、以下の3つのファイルが生成されます。
- MyItem.cs
- MyItem.xib
- MyItemController.cs
操作の対象を、MyItemController.csとしたいのですが、これをプロトタイプとしてビューコントローラーを登録するとき、xibと名前が一致している必要があるため、MyItem.xibをMyItemController.xibに変更します。
続いて、CollectionViewItem.xibをInterface Builderで開いて、Boxを配置し、ビューいっぱいに表示されるように制約を追加します。Boxは、デフォルトでタイトル(Box)が表示される状態になっているので、とりあえずそのままにしておきます。
MyItemControllerクラスは、NSCollectionViewItemを継承するように書き換えます。
MyItemController.cs
public partial class MyItemController : NSCollectionViewItem { #region Constructors // Called when created from unmanaged code public MyItemController(IntPtr handle) : base(handle) { Initialize(); }
4 DataSource/Delegate
コレクションビューのデリゲートクラスとしてNSCollectionViewDelegateFlowLayoutを継承した、CollectionViewDelegateクラスを作成します。
NSCollectionViewDelegateFlowLayoutは、組み込みのレイアウト型です。
using AppKit; namespace Sample001 { public class CollectionViewDelegate : NSCollectionViewDelegateFlowLayout { public CollectionViewDelegate() { } } }
データクラスは、NSCollectionViewDataSourceを継承して作成します。
GetNumberofItems()は、データ数を返すメソッドですが、ここでは、仮に10個アイテムがあるという想定で、10を返しておきます。
GetItem()は、ここのアイテム(NSCollectionViewItem)を返すメソッドなので、MyItemControllerクラスを生成して返しています。
namespace Sample001 { public class CollectionViewDataSource: NSCollectionViewDataSource { public CollectionViewDataSource() { } public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) { var item = collectionView.MakeItem("cell", indexPath) as MyItemController; return item; } public override nint GetNumberofItems(NSCollectionView collectionView, nint section) { return 10; } } }
5 初期化
最後に、ViewControllerのViewDidLoad()で、コレクションビューの初期化を行います。
NSCollectionViewFlowLayout() で、150✕150のレイアウトを定義して、コレクションビューに設定してます。(①)
個々のアイテムを表示するために準備した、MyItemControllerは、RegisterClassForItemでコレクションビューに登録しています。(②)
Delegate及び、DataSourceも、通常通り登録しています。(③、④)
public partial class ViewController : NSViewController { public ViewController(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); // MyItemControllerの登録(②) CollectionView.RegisterClassForItem(typeof(MyItemController), "cell"); // DataSource(③) CollectionView.DataSource = new CollectionViewDataSource(); // Flow layout(①) var flowLayout = new NSCollectionViewFlowLayout() { ItemSize = new CGSize(150, 150), SectionInset = new NSEdgeInsets(10, 10, 10, 20), MinimumInteritemSpacing = 10, MinimumLineSpacing = 10 }; CollectionView.WantsLayer = true; CollectionView.CollectionViewLayout = flowLayout; // Delegate(④) CollectionView.Delegate = new CollectionViewDelegate(); }
ここまでの実装で、10個のアイテムが表示されていることを確認できます。
6 データ表示
元となるデータクラスは、下記で作成したものを使用します。
Product.cs
[Register("Product")] public class Product : NSObject { private string _name; private int _price; public Product(string name, int price) { _name = name; _price = price; } [Export("Name")] public string Name { get { return _name; } set { WillChangeValue("Name"); _name = value; DidChangeValue("Name"); } } [Export("Price")] public int Price { get { return _price; } set { WillChangeValue("Name"); _price = value; DidChangeValue("Name"); } } }
MyItemControllerで、データクラスをプロパティとして定義します。
MyItemController.cs
public partial class MyItemController : NSCollectionViewItem { // 商品(Product)クラスを定義 private Product _product; // 商品(Product)クラスを公開 [Export("Product")] public Product Product { get { return _product; } set { WillChangeValue("Product"); _product = value; DidChangeValue("Product"); } }
ビューにLabelを追加して、公開されたプロパティにバインディングします。
データソースで商品クラスの配列(Data)を定義し、GetItem() 及び、GetNumberofItems() で、それを返すように書き換えます。
CollectionViewDataSource.cs
public class CollectionViewDataSource: NSCollectionViewDataSource { public List<Product> Data; public CollectionViewDataSource() { } public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) { var item = collectionView.MakeItem("cell", indexPath) as MyItemController; item.Product = Data[(int)indexPath.Item]; return item; } public override nint GetNumberofItems(NSCollectionView collectionView, nint section) { return Data.Count; } }
データソースのデータは、ViewControllerのViewDidLoadで生成します。
ViewController.cs
<br />public partial class ViewController : NSViewController { public override void ViewDidLoad() { base.ViewDidLoad(); // ・・・略・・・ // データ var Products = new List<Product>(); Products.Add(new Product("AAA", 100)); Products.Add(new Product("BBB", 120)); Products.Add(new Product("CCC", 1300)); Products.Add(new Product("DDD", 220)); Products.Add(new Product("EEE", 950)); ((CollectionViewDataSource)CollectionView.DataSource).Data = Products; }
実行すると、定義した商品データの表示を確認できます。
7 最後に
今回は、コレクションビューを使用してみました。
アイテム用のビューの準備や、レイアウト定義など、色々作業が多くなっています。また、データバインディングも必須となることから、やはり、コレクションビューの利用は、ちょっと大変です。